package cn.wangyu.msblogadmin.handle;


import cn.wangyu.msblogadmin.common.exception.BusinessException;
import cn.wangyu.msblogadmin.common.result.ResponseCode;
import cn.wangyu.msblogadmin.common.result.ResultModel;
import cn.wangyu.msblogadmin.common.utils.ResultUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.TypeMismatchException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.validation.ConstraintViolationException;
import java.util.List;

/**
 * @author wangyu
 * @version 1.0
 * @date 2021/4/11 23:12
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 拦截捕捉自定义异常 BusinessException
     */
    @ExceptionHandler(value = BusinessException.class)
    public ResultModel businessExceptionHandler(BusinessException ex) {
        log.error(ex.getMessage(), ex);
        return ResultUtil.error(ex.getResponseCode(), ex.getMessage());
    }

    /**
     * 捕捉空指针异常
     */
    @ExceptionHandler({NullPointerException.class})
    public ResultModel nullPointerExceptionHandler(NullPointerException ex) {
        ex.printStackTrace();
        log.error(ex.getMessage(), ex);
        return ResultUtil.error(ResponseCode.NULL_POINTER, ex.getMessage());
    }

    /**
     * 捕捉IllegalArgumentException 非法参数异常
     */
    @ExceptionHandler({IllegalArgumentException.class})
    public ResultModel illegalArgumentExceptionHandler(IllegalArgumentException ex) {
        ex.printStackTrace();
        log.error(ex.getMessage(), ex);
        return ResultUtil.error(ResponseCode.ILLEGAL_ARGUMENT, ex.getMessage());
    }

    /**
     * 捕捉全局异常
     */
    @ExceptionHandler(value = BindException.class)
    public ResultModel globalExceptionHandler(Exception ex) {
        log.error(ex.getMessage(), ex);
        if (ex instanceof BindException) {
            BindException e = (BindException) ex;
            List<ObjectError> errors = e.getAllErrors();
            //获取自错误信息
            String errorMsg = errors.get(0).getDefaultMessage();
            Class<? extends ObjectError> aClass = errors.get(0).getClass();
            return ResultUtil.error(ResponseCode.FAILED, errorMsg);
        }
        return ResultUtil.error(ResponseCode.FAILED, ex.getMessage());
    }

    /**
     * 拦截参数不匹配异常 400 getPropertyName()获取数据类型不匹配参数名称  getRequiredType()实际要求客户端传递的数据类型
     */
    @ExceptionHandler(value = TypeMismatchException.class)
    public ResultModel requestTypeMismatch(TypeMismatchException ex) {
        //拼接详细错误信息
        StringBuilder sb = new StringBuilder();
        sb.append("参数类型不匹配,参数：").append(ex.getPropertyName());
        sb.append("类型应该为：" + ex.getRequiredType());
        log.error(ex.getMessage(), ex);
        ex.printStackTrace();
        return ResultUtil.error(ResponseCode.REQUEST_PARAM_MISMATCH, ex.getMessage());
    }

    /**
     * 缺少参数异常 getParameterName() 缺少的参数名称 400
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    @ResponseBody
    public ResultModel requestMissingServletRequest(MissingServletRequestParameterException ex) {
        log.error(ex.getMessage(), ex);
        ex.printStackTrace();
        return ResultUtil.error(ResponseCode.REQUEST_PARAM_MISSING, ex.getMessage());
    }

    /**
     * 404 请求地址不存在或错误
     */
    @ExceptionHandler(value = NoHandlerFoundException.class)
    @ResponseBody
    public ResultModel noSuchRequestHandlingRequest(NoHandlerFoundException ex) {
        log.error(ex.getMessage(), ex);
        ex.printStackTrace();
        return ResultUtil.error(ResponseCode.REQUEST_NOT_FOUND, ex.getMessage());
    }

    /**
     * 405 不正确的请求方式
     */
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public ResultModel methodNotSupportedRequest(HttpRequestMethodNotSupportedException ex) {
        log.error(ex.getMessage(), ex);
        ex.printStackTrace();
        return ResultUtil.error(ResponseCode.REQUEST_METHOD_NOT_SUPPORTED, ex.getMessage());
    }

    /**
     * hibernate validate 类注解校验异常拦截
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public ResultModel methodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.error(ex.getMessage(), ex);
        ex.printStackTrace();
        String defaultMessage = ex.getBindingResult().getAllErrors().get(0).getDefaultMessage();
        return ResultUtil.error(ResponseCode.REQUEST_PARAM_EMPTY, defaultMessage);
    }

    /**
     * hibernate validate 单个参数注解校验异常拦截
     *
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(ConstraintViolationException.class)
    public ResultModel handleConstraintException(ConstraintViolationException ex) {
        log.error(ex.getMessage(), ex);
        ex.printStackTrace();
        return ResultUtil.error(ResponseCode.REQUEST_PARAM_EMPTY, ex.getMessage());
    }
}
